﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PintTool
{
    public partial class FrmMain : Form
    {
        const string pattern = @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$";

        readonly Dictionary<string, CancellationTokenSource> _tokens = new Dictionary<string, CancellationTokenSource>();

        bool _pingSuccessLog = false;
        bool _pingWriteSuccessLog = false;
        int _pingInterval = 1000;

        public FrmMain()
        {
            InitializeComponent();

            lbIPs.Items.Clear();
            lbLog.Items.Clear();

            btnStart.Enabled = true;
            btnStop.Enabled = false;
        }

        private void FrmMain_Shown(object sender, EventArgs e)
        {
            ReadIPs();
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            var ip = txtIP.Text.Trim();
            var b = Regex.IsMatch(ip, pattern);
            if (!b)
            {
                MessageBox.Show("错误的IP地址");
                return;
            }

            var exIP = lbIPs.Items.Cast<string>().FirstOrDefault(t => t == ip);
            if (exIP != null)
            {
                MessageBox.Show("IP存在");
                return;
            }

            lbIPs.Items.Add(ip);
            txtIP.Clear();

            WriteIPs();
        }

        private void btnDel_Click(object sender, EventArgs e)
        {
            if (lbIPs.SelectedItem == null)
            {
                MessageBox.Show("请选择要删除的IP");
                return;
            }

            if (_tokens.ContainsKey(lbIPs.SelectedItem.ToString()))
            {
                _tokens[lbIPs.SelectedItem.ToString()].Cancel();
                _tokens.Remove(lbIPs.SelectedItem.ToString());
            }
            lbIPs.Items.Remove(lbIPs.SelectedItem);

            WriteIPs();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            btnStart.Enabled = false;

            _pingInterval = (int)numPingInterval.Value;
            _pingSuccessLog = chkSuccessLog.Checked;
            _pingWriteSuccessLog = chkWritePingSuccess.Checked;

            lbIPs.Items.Cast<string>().ToList().ForEach(ip =>
            {
                var source = new CancellationTokenSource();
                var token = source.Token;

                _tokens.Add(ip, source);

                Task.Run(async () =>
                {
                    var ping = new Ping();

                    while (true)
                    {
                        if (token.IsCancellationRequested) return;

                        // 最多等待3秒
                        var pr = ping.Send(ip, 3000);
                        if (pr.Status != IPStatus.Success)
                        {
                            WriteLog(ip, $"【{ip}】【{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}】 Ping丢失", false);
                        }
                        else
                            WriteLog(ip, $"【{ip}】【{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}】 Ping通【{pr.RoundtripTime}】");

                        Task.Delay(_pingInterval).Wait();
                    }
                });
            });

            btnStop.Enabled = true;
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            btnStop.Enabled = false;
            foreach (var kv in _tokens)
            {
                kv.Value.Cancel();
            }

            _tokens.Clear();
            btnStart.Enabled = true;
        }

        void WriteLog(string ip, string msg, bool success = true)
        {
            if (_pingSuccessLog)
                lbLog.BeginInvoke(new Action(() =>
                {
                    if (lbLog.Items.Count >= 500)
                    {
                        lbLog.Items.RemoveAt(499);
                    }
                    lbLog.Items.Insert(0, msg);
                }));

            if (!success)
                LogHelper.WriteLog(ip, msg);
            else if (_pingWriteSuccessLog)
                LogHelper.WriteLog(ip, msg);
        }

        readonly string _path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "iplist.txt");

        void ReadIPs()
        {
            if (!File.Exists(_path)) return;

            var txt = File.ReadAllText(_path);
            if (string.IsNullOrWhiteSpace(txt)) return;

            var ips = txt.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries).ToList();

            ips.ForEach(ip => lbIPs.Items.Add(ip));
        }
        void WriteIPs()
        {
            using (File.Create(_path)) { }

            if (lbIPs.Items.Count <= 0) return;

            using (var sw = File.AppendText(_path))
            {
                lbIPs.Items.Cast<string>().ToList().ForEach(ip => sw.WriteLine(ip));

                sw.Flush();
                sw.Close();
                sw.Dispose();
            }
        }

        private void chkSuccessLog_CheckedChanged(object sender, EventArgs e)
        {
            _pingSuccessLog = chkSuccessLog.Checked;
        }

        private void FrmMain_Load(object sender, EventArgs e)
        {

        }
    }
}
